#include "Socket.h"

//创建非阻塞的fd
int createnonblocking()
{
    //创建用于监听的fd                            SOCK_NONBLOCK设置为非阻塞
    int listenfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
    if(listenfd < 0)
    {
        //perror("socket() failed");
        //exit(-1);
        printf("%s:%s:%d listen socket create error:%d\n", __FILE__, __FUNCTION__, __LINE__, errno);
        exit(-1);
    }

    return listenfd;
}

Socket::Socket(int fd):fd_(fd)
{

}

Socket::~Socket()
{
    ::close(fd_);
}

int Socket::fd() const
{
    return fd_;
}

std::string Socket::ip() const     //返回ip地址
{
    return ip_;
}

uint16_t Socket::port() const      //返回端口
{
    return port_;
}

void Socket::setreuseaddr(bool on) //设置SO_REUSEADDR选项，ture-打开，false-关闭
{
    int optval = on ? 1 : 0;
    ::setsockopt(fd_, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
}

void Socket::setreuseport(bool on) //设置SO_REUSERPORT选项
{
    int optval = on ? 1 : 0;
    ::setsockopt(fd_, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
}

void Socket::settcpnodelay(bool on) //设置TCP_NODELAY选项
{
    int optval = on ? 1 : 0;
    ::setsockopt(fd_, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
}

void Socket::setkeepalive(bool on) //设置SO_KEEPALIVE选项
{
    int optval = on ? 1 : 0;
    ::setsockopt(fd_, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval));
}

void Socket::bind(const InetAddress& servaddr) //服务端的socket将调用该函数
{
    if(::bind(fd_, servaddr.addr(), sizeof(sockaddr)) < 0)
    {
        perror("bind() failed");
        close(fd_);
        exit(-1);
    }

    set_IP_PORT(servaddr);
}

void Socket::listen(int listen_Num)
{
    if(::listen(fd_, listen_Num) != 0)
    {
        perror("listen() failed");
        close(fd_);
        exit(-1);
    }
}

int Socket::accept(InetAddress& clientaddr)
{
    sockaddr_in peeraddr;
    socklen_t len = sizeof(peeraddr);
    //accept4函数可以用SOCK_NONBLOCK设置IO非阻塞
    int clientfd = accept4(fd_, (sockaddr*)&peeraddr, &len, SOCK_NONBLOCK);
                    
    clientaddr.setaddr(peeraddr);
    return clientfd;
}

void Socket::set_IP_PORT(const InetAddress& addr)
{
    ip_ = addr.ip();
    port_ = addr.port();
}